package funcionesDeCruce;

import java.util.ArrayList;

import util.Aleatorio;

import cromosomas.Arbol;
import cromosomas.CromosomaEstrategia;
import elementosEvolutivos.Cromosoma;
import elementosEvolutivos.FuncCruce;

public class IntercambioSubarboles implements FuncCruce {

	@Override
	public Cromosoma[] cruce(Cromosoma cr1, Cromosoma cr2) {
		CromosomaEstrategia[] hijos = new CromosomaEstrategia[2];
		CromosomaEstrategia cre1 = (CromosomaEstrategia)cr1.clone();
		CromosomaEstrategia cre2 = (CromosomaEstrategia)cr2.clone();
		double selinternos = Aleatorio.getDoubleAleatorio();
		int pos1=0;
		int pos2=0;
		ArrayList<Arbol> nodos1 = obtenerNodos(cre1.getArbol());
		ArrayList<Arbol> nodos2 = obtenerNodos(cre2.getArbol());
		ArrayList<Arbol> nodosInternos1 = obtenerNodosInternos(cre1.getArbol());
		ArrayList<Arbol> nodosInternos2 = obtenerNodosInternos(cre2.getArbol());
		Arbol aux = new Arbol(null);
		if(selinternos<0.9){
			if(nodosInternos1.size()!=0 && nodosInternos2.size()!=0){
				pos1=Aleatorio.getIntAleatorio(nodosInternos1.size());
				pos2=Aleatorio.getIntAleatorio(nodosInternos2.size());
				while(nodosInternos1.get(pos1).getProfundidad()!=nodosInternos2.get(pos2).getProfundidad()){
					pos1=Aleatorio.getIntAleatorio(nodosInternos1.size());
					pos2=Aleatorio.getIntAleatorio(nodosInternos2.size());
				}
				aux.setArbol(nodosInternos1.get(pos1));
				aux.setPadre(nodosInternos1.get(pos1).getPadre());
				nodosInternos1.get(pos1).setArbol(nodosInternos2.get(pos2));
				nodosInternos2.get(pos2).setArbol(aux);
			}
		}
		else{
			pos1=Aleatorio.getIntAleatorio(nodos1.size());
			pos2=Aleatorio.getIntAleatorio(nodos2.size());
			while(nodos1.get(pos1).getProfundidad()!=nodos2.get(pos2).getProfundidad()){
				pos1=Aleatorio.getIntAleatorio(nodos1.size());
				pos2=Aleatorio.getIntAleatorio(nodos2.size());
			}
			aux.setArbol(nodos1.get(pos1));
			aux.setPadre(nodos1.get(pos1).getPadre());
			nodos1.get(pos1).setArbol(nodos2.get(pos2));
			nodos2.get(pos2).setArbol(aux);
		}
		hijos[0]=cre1;
		hijos[1]=cre2;
		return hijos;
	}
	
	private ArrayList<Arbol> obtenerNodos(Arbol ar){
		ArrayList <Arbol> listaNodos = new ArrayList<Arbol>();
		listaNodos.add(ar);
		for(int i=0; i<ar.getNum_hijos(); i++)
			listaNodos.addAll(obtenerNodos(ar.getHijos()[i]));
		return listaNodos;
	}
	
	private ArrayList<Arbol> obtenerNodosInternos(Arbol ar){
		ArrayList <Arbol> listaNodosInternos = new ArrayList<Arbol>();
		if(ar.isNodo()&&ar.getProfundidad()!=0)
			listaNodosInternos.add(ar);
		for(int i=0; i<ar.getNum_hijos(); i++)
			listaNodosInternos.addAll(obtenerNodosInternos(ar.getHijos()[i]));
		return listaNodosInternos;
	}

}
